package xtu.www.viewinject.net;

import org.json.JSONObject;

import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import android.support.annotation.IntDef;
import android.support.annotation.StringDef;
import android.text.TextUtils;
import android.util.Log;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;
import rx.Subscriber;


/**
 * NetTask Worker
 * Created by zhangzhang on 2016/12/12.
 */
public class NetTask {

    /**
     * NetTask Error
     */
    // ERRNO
    public static final int ERRNO_SUCCESS = 0;
    public static final int ERRNO_PARSE_ERROR = -1000000;  // Negative Number For App
    public static final int ERRNO_NET_ERROR = -1000001;  // Negative Number For App

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({ERRNO_SUCCESS, ERRNO_NET_ERROR, ERRNO_PARSE_ERROR})
    @interface NET_ERRNO {}

    // ERRMSG
    public static final String ERRNO_SUCCESS_MSG = "请求成功";
    public static final String ERRNO_NET_ERROR_MSG = "网络请求失败，请重试";
    public static final String ERRNO_PARSE_ERROR_MSG = "网络错误，请稍后重试";

    @Retention(RetentionPolicy.SOURCE)
    @StringDef({ERRNO_SUCCESS_MSG, ERRNO_NET_ERROR_MSG, ERRNO_PARSE_ERROR_MSG})
    @interface NET_ERRMSG {}

    /**
     * Log Tag
     */
    private static String TAG = "";

    private static Map<String, String> mCommonParam;

    /**
     * Network Time Out
     */
    private static final int TIME_OUT = 12;

    static {
        TAG = NetTask.class.getSimpleName();

    }

    private static NetTask mInstance = null;

    private OkHttpClient mOkHttpClient = null;
    private Retrofit mRetrofit = null;

    private static String getBaseURL() {
        return "http://t800.chemanman.com/";
    }

    private NetTask() {
        if (mOkHttpClient == null) {
            mOkHttpClient = new OkHttpClient.Builder().retryOnConnectionFailure(false)
                                                      .addInterceptor(new NetInterceptor())
                                                      .connectTimeout(TIME_OUT, TimeUnit.SECONDS)
                                                      .readTimeout(TIME_OUT, TimeUnit.SECONDS)
                                                      .writeTimeout(TIME_OUT, TimeUnit.SECONDS)
                                                      .cache(null)
                                                      .build();
        }
    }

    public String getHost(){
        return getBaseURL();
    }

    public static NetTask getInstance() {
        if (mInstance == null) {
            synchronized (NetTask.class) {
                if (mInstance == null) {
                    mInstance = new NetTask();
                }
            }
        }

        return mInstance;
    }

    public <T> T create(Class<T> service) {
        if (mRetrofit == null) {
            flushBaseUrl();
        }

        return mRetrofit.create(service);
    }

    public void flushBaseUrl() {

        mRetrofit = new Retrofit.Builder().baseUrl(getBaseURL())
                                          .client(mOkHttpClient)
                                          .addConverterFactory(ScalarsConverterFactory.create())
                                          .addConverterFactory(GsonConverterFactory.create())
                                          .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                                          .build();
    }

    public Subscriber<String> onSubscriber(final MMCallback callback) {
        return new Subscriber<String>() {
            @Override
            public void onCompleted() {
                ;
            }

            @Override
            public void onError(Throwable throwable) {
                Log.d(TAG, "[Fail]" + throwable.toString());
                MMResponse response = new MMResponse();
                response.setErrno(ERRNO_NET_ERROR);
                response.setErrmsg(ERRNO_NET_ERROR_MSG);
                callback.onError(response);
            }

            @Override
            public void onNext(String o) {
                MMResponse response = new MMResponse();

                try {
                    JSONObject jsonObject = SimpleTokener.getOneLevelJOSNObject(o);

                    // 兼容新旧两个后端的数据结构
                    String res = jsonObject.has("res") ? jsonObject.optString("res", "") : jsonObject.optString("data", "");

                    Log.d(TAG, jsonObject.toString());

                    if (jsonObject.optInt("errno") == -1) {
                        // 未登陆


                    }

                    response.setErrno(jsonObject.optInt("errno"));
                    response.setErrmsg(jsonObject.optString("errmsg"));
                    response.setData(res);
                } catch (Exception e) {
                    Log.d(TAG, e.toString());

                    response.setErrno(ERRNO_PARSE_ERROR);
                    response.setErrmsg(ERRNO_PARSE_ERROR_MSG);
                }

                if (ERRNO_SUCCESS == response.getErrno()) {
                    callback.onSuccess(response);
                } else {
                    callback.onError(response);
                }
            }
        };
    }

    private class NetInterceptor implements Interceptor {

        private String body(RequestBody requestBody) {
            Buffer buffer = new Buffer();

            if (requestBody != null) {
                try {
                    requestBody.writeTo(buffer);

                    return buffer.readUtf8();
                } catch (IOException e) {
                    return "";
                }
            } else {
                return "";
            }
        }

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request oldRequest = chain.request();
            Request request;

            // Common Params
            Request.Builder requestBuilder = oldRequest.newBuilder();
            if (oldRequest.method().equals("POST")) {
                // Add Form Filed If POST
                if (oldRequest.body() instanceof MultipartBody) {
                    // FIXME IF NEED
                    request = oldRequest;
                } else {
                    FormBody.Builder bodyBuilder = new FormBody.Builder();

                    for (Map.Entry<String, String> entry : mCommonParam.entrySet()) {
                        bodyBuilder.add(entry.getKey(), entry.getValue());
                    }

                    ArrayList<String> sBody = new ArrayList<>();
                    sBody.add(body(oldRequest.body()));
                    sBody.add(body(bodyBuilder.build()));
                    RequestBody newBody = RequestBody.create(oldRequest.body().contentType(), TextUtils
                            .join("&", sBody));

                    requestBuilder.addHeader("Connection", "close");
                    request = requestBuilder.method(oldRequest.method(), newBody).build();
                }
            } else {
                // Add URL Params
                HttpUrl.Builder authorizedUrlBuilder = oldRequest.url()
                                                                 .newBuilder()
                                                                 .scheme(oldRequest.url().scheme())
                                                                 .host(oldRequest.url().host());

//                for (Map.Entry<String, String> entry : mCommonParam.entrySet()) {
//                    authorizedUrlBuilder.addQueryParameter(entry.getKey(), entry.getValue());
//                }

                requestBuilder.addHeader("Connection", "close");
                request = requestBuilder.url(authorizedUrlBuilder.build()).build();
            }

            Log.d(TAG, String.format(Locale.getDefault(),
                                     "[URL][Request] %s\n",
                                     request.toString()));

            // Cal request
            long t1 = System.nanoTime();
            okhttp3.Response response = chain.proceed(request);
            long t2 = System.nanoTime();

            // Print response info
            Log.d(TAG, String.format(Locale.getDefault(),
                                     "[URL][Response] %s\n[Time] %.1fms\n[Content-Length] %d\n[MediaType] %s\n[Header] %n%s",
                                     response.request().url(),
                                     (t2 - t1) / 1e6d,
                                     response.body().contentLength(),
                                     response.body().contentType(),
                                     response.headers()));

            // Don't rebuild response, Don't print response in here.
            return response;
        }
    }
}
